﻿using System;
using Sunny.Core.Exception;

namespace Sunny.Core.DefinedData
{
    public struct SFloat : IComparable<SFloat>
    {
        private readonly decimal? _number;

        public SFloat(decimal? value)
        {
            this._number = value;
        }

        #region Implicit Operator WebEziFloat

        public static implicit operator SFloat(string value)
        {
            if (String.IsNullOrEmpty(value))
            {
                return new SFloat(null);
            }
            else
            {
                decimal tempNumber;

                if (decimal.TryParse(value, out tempNumber))
                {
                    return new SFloat(tempNumber);
                }
                else
                {
                    throw new DefinedDataException("The source value is " + value);
                }
            }
        }

        public static implicit operator SFloat(decimal? value)
        {
            return new SFloat(value);
        }

        public static implicit operator SFloat(double? value)
        {
            if(value.HasValue)
            {
                decimal tempNumber;
                if(decimal.TryParse(value.ToString(), out tempNumber))
                {
                    return new SFloat(tempNumber);
                }
                else
                {
                    throw new DefinedDataException("The number is " + value + ", can't convert to decimal.");
                }
            }
            else
            {
                return  new SFloat(null);
            }
        }

        public static implicit operator SFloat(float? value)
        {
            if (value.HasValue)
            {
                decimal tempNumber;
                if (decimal.TryParse(value.ToString(), out tempNumber))
                {
                    return new SFloat(tempNumber);
                }
                else
                {
                    throw new DefinedDataException("The number is " + value + ", can't convert to decimal.");
                }
            }
            else
            {
                return new SFloat(null);
            }
        }

        #endregion

        #region Implicit Operator Other

        public static implicit operator string(SFloat value)
        {
            return value._number.ToString();
        }

        public static implicit operator decimal(SFloat value)
        {
            if (!value._number.HasValue)
            {
                return 0;
            }

            return value._number.Value;
        }

        public static implicit operator decimal?(SFloat value)
        {
            return value._number;
        }

        public static implicit operator double(SFloat value)
        {
            if (value._number.HasValue)
            {
                double tempValue;
                if (double.TryParse(value._number.Value.ToString(), out tempValue))
                {
                    return tempValue;
                }
                else
                {
                    throw new DefinedDataException("The number is " + value._number.Value + ",can't convert to double.");
                }
            }
            else
            {
                return 0;
            }
        }

        public static implicit operator double?(SFloat value)
        {
            if (value._number.HasValue)
            {
                double tempValue;
                if (double.TryParse(value._number.Value.ToString(), out tempValue))
                {
                    return tempValue;
                }
                else
                {
                    throw new DefinedDataException("The number is " + value._number.Value + ",can't convert to double.");
                }
            }
            else
            {
                return null;
            }
        }

        public static implicit operator float(SFloat value)
        {
            if (value._number.HasValue)
            {
                float tempValue;
                if (float.TryParse(value._number.Value.ToString(), out tempValue))
                {
                    return tempValue;
                }
                else
                {
                    throw new DefinedDataException("The number is " + value._number.Value + ",can't convert to float.");
                }
            }
            else
            {
                return 0;
            }
        }

        public static implicit operator float?(SFloat value)
        {
            if (value._number.HasValue)
            {
                float tempValue;
                if (float.TryParse(value._number.Value.ToString(), out tempValue))
                {
                    return tempValue;
                }
                else
                {
                    throw new DefinedDataException("The number is " + value._number.Value + ",can't convert to float.");
                }
            }
            else
            {
                return null;
            }
        }

        #endregion

        #region Implicit Operator

        public static bool operator ==(SFloat x, SFloat y)
        {
            return x._number == y._number;
        }

        public static bool operator !=(SFloat x, SFloat y)
        {
            return x._number != y._number;
        }

        public static bool operator <(SFloat x, SFloat y)
        {
            return x._number < y._number;
        }

        public static bool operator >(SFloat x, SFloat y)
        {
            return x._number > y._number;
        }

        public static bool operator <= (SFloat x, SFloat y)
        {
            return x._number <= y._number;
        }

        public static bool operator >= (SFloat x, SFloat y)
        {
            return x._number >= y._number;
        }

        #endregion

        public override string ToString()
        {
            return _number.ToString();
        }

        /// <summary>
        /// Return the value is null
        /// </summary>
        /// <returns>The value is null</returns>
        public bool IsNull()
        {
            return !_number.HasValue;
        }

        #region IComparable<WebEziFloat> Members

        public int CompareTo(SFloat other)
        {
            if (_number.HasValue)
            {
                return _number.Value.CompareTo(other._number);
            }
            else if (!other._number.HasValue)
            {
                return 0;
            }
            else
            {
                return -1;
            }
        }

        #endregion

        public bool Equals(SFloat obj)
        {
            return obj._number.Equals(_number);
        }

        public override bool Equals(object obj)
        {
            if (obj.GetType() != typeof (SFloat)) return false;
            return Equals((SFloat) obj);
        }

        public override int GetHashCode()
        {
            return (_number.HasValue ? _number.Value.GetHashCode() : 0);
        }
    }
}
